package com.gitee.limaozhi.nio.example03;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketOption;
import java.net.SocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author hzlimaozhi
 * @date 2019/12/20 14:55
 */
public class Server {

    public static void main(String[] args) throws IOException {
        // 1. 创建监听Channel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 2. 设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        // 3. 绑定端口
        serverSocketChannel.bind(new InetSocketAddress(8000));

        // 4. 创建Selector
        Selector selector = Selector.open();
        // 5. 向Selector注册事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("服务器启动");

        while (true) {
            // 6. 查询就绪通道和事件
            if (selector.select(10) <= 0) {
                continue;
            }

            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();

                if (selectionKey.isValid() && selectionKey.isAcceptable()) {
                    System.out.println("\nAcceptable");
                    handleAcceptable(selectionKey);
                }

                if (selectionKey.isValid() && selectionKey.isReadable()) {
                    System.out.println("\nReadable");
                    handleReadable(selectionKey);
                }

                if (selectionKey.isValid() && selectionKey.isWritable()) {
                    System.out.println("\nWritable");
                    handleWritable(selectionKey);
                }
            }
        }
    }

    private static void handleAcceptable(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
        SocketChannel socketChannel = serverSocketChannel.accept();
        if (socketChannel != null) {
            System.out.println("连接建立：" + socketChannel.getRemoteAddress());
            socketChannel.configureBlocking(false);
            socketChannel.socket().setReceiveBufferSize(512);
            socketChannel.socket().setTcpNoDelay(true);
            socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        } else {
            System.out.println("无连接");
        }
    }

    private static void handleReadable(SelectionKey selectionKey) throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

        // 读缓冲
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        readBuffer.clear();

        int count = socketChannel.read(readBuffer);
        if (count > 0) {
            System.out.println("读取：" + count);
            ack(socketChannel);

        } else if (count == 0) {
            System.out.println("无可读");
            ack(socketChannel);

        } else {
            System.out.println("对方关闭写通道");
            ack(socketChannel);

            System.out.println("关闭Socket");
            selectionKey.cancel();
            socketChannel.close();
        }
    }

    private static void ack(SocketChannel socketChannel) throws IOException {
        byte[] ack = "ok".getBytes();
        ByteBuffer byteBuffer = ByteBuffer.allocate(ack.length);
        byteBuffer.clear();
        byteBuffer.put(ack);
        byteBuffer.flip();
        socketChannel.write(byteBuffer);
    }

    private static void handleWritable(SelectionKey selectionKey) {
        //
    }

}
